﻿using ZeroBug.EasyFlow.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ZeroBug.EasyFlow.Motion
{
    public class Axis : IMachineResource<IAxis>, IResourceVariable
    {
        private bool _inMove;
        [XmlIgnore]
        public IAxis AxisOperator { get; set; }
        public short CardNo { get; set; }
        public short AxisNo { get; set; }
        public string Description { get; set; }
        public bool IsStep { get; set; }
        public string ID { get; set; }
        public bool IsRotateAxis { get; set; }
        [NumericVariable]
        public double ConvertRate { get; set; } = 1;
        public string Module { get; set; }
        public double PositionBand { get; set; } = 0.05;
        public bool IsAbsoluteEncoder { get; set; }
        public bool HomeDirP { get; set; }
        public int HomeMode { get; set; }
        public double HomeOffset { get; set; }
        [XmlIgnore]
        public bool CurrentDirection { get; set; }
        /// <summary>
        ///
        /// </summary>
        public double[] SettingVelStart { get; set; }
        /// <summary>
        /// 0---home  1----run 2---debug
        /// </summary>
        [NumericVariable]
        public double[] SettingVel { get; set; }
        /// <summary>
        ///
        /// </summary>
        public double[] SettingVelEnd { get; set; }
        public double[] SettingAcc { get; set; }
        public double[] SettingDec { get; set; }
        public double[] SettingSTime { get; set; }
        public SerializableDictionary<string, double> Distance2Pos { get; set; } = new SerializableDictionary<string, double>();
        public SerializableDictionary<string, double> MotionPosition { get; set; }
        [XmlIgnore]
        public bool NoCheckLimit { get; set; } = false;
        [XmlIgnore]
        public bool StopMovement { get; set; } = false;
        private double _vel;
        [XmlIgnore]
        public double Vel
        {
            set
            {
                _vel = AxisOperator.VelUnitConvert(MM2Pulse(value));
            }
            get
            {
                return _vel;
            }
        }
        private double _changedVel;
        [XmlIgnore]
        public double ChangedVel
        {
            set
            {
                _changedVel = AxisOperator.VelUnitConvert(MM2Pulse(value));
            }
            get
            {
                return _changedVel;
            }
        }
        private double _velStart;
        [XmlIgnore]
        public double VelStart
        {
            set
            {
                _velStart = AxisOperator.VelUnitConvert(MM2Pulse(value));
            }
            get
            {
                return _velStart;
            }
        }
        private double _velEnd;
        [XmlIgnore]
        public double VelEnd
        {
            set
            {
                _velEnd = AxisOperator.VelUnitConvert(MM2Pulse(value));
            }
            get
            {
                return _velEnd;
            }
        }
        private double _acc;
        [XmlIgnore]
        public double Acc
        {
            set
            {
                _acc = AxisOperator.AccUnitConvert(_vel, value);
            }
            get
            {
                return _acc;
            }
        }
        private double _changedAcc;
        [XmlIgnore]
        public double ChangedAcc
        {
            set
            {
                _changedAcc = AxisOperator.AccUnitConvert(_vel, value);
            }
            get
            {
                return _changedAcc;
            }
        }
        private double _dec;
        [XmlIgnore]
        public double Dec
        {
            set
            {
                _dec = AxisOperator.AccUnitConvert(_vel, value);
            }
            get
            {
                return _dec;
            }
        }
        private double _sTime;
        [XmlIgnore]
        public double STime
        {
            set
            {
                _sTime = AxisOperator.AccUnitConvert(_vel, value);
            }
            get
            {
                return _sTime;
            }
        }
        [XmlIgnore]
        public bool ServoWarn
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).ServoWarn;
            }
        }
        [XmlIgnore]
        public bool Origin
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).Origin;
            }
        }
        [XmlIgnore]
        public bool PositiveLimit
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).PositiveLimit;
            }
        }
        [XmlIgnore]
        public bool NegativeLimit
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).NegativeLimit;
            }
        }
        [XmlIgnore]
        public bool Ready
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).Ready;
            }
        }
        [XmlIgnore]
        public bool EmergencyStop
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).EmergencyStop;
            }
        }
        [XmlIgnore]
        public bool ServoOn
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).ServoOn;
            }
        }
        [XmlIgnore]
        public bool Home
        {
            get
            {
                return AxisOperator.GetAxisHomeFound(CardNo, AxisNo);
            }
        }
        [XmlIgnore]
        public bool ReachPosition
        {
            get
            {
                return AxisOperator.GetAxisStatus(CardNo, AxisNo).ReachPosition;
            }
        }
        [XmlIgnore]
        [TextVariable]
        public double Position
        {
            get
            {
                return new Random().NextDouble();
                return IsStep ? Pulse2MM((int)AxisOperator.GetAxisCommandPosition(CardNo, AxisNo)) : Pulse2MM((int)AxisOperator.GetAxisEncoderPosition(CardNo, AxisNo));
            }
        }
        public List<MotionLimit> AxisLimits { get; set; }
        public List<PositionLimit> PositionLimits { get; set; }
        public List<SensorLimit> SensorLimits { get; set; }
        /// <summary>
        /// 0-Up&Left2Right,1-Down&Left2Right,2-Up&Right2Left,3-Down&Right2Left
        /// 4-Left&Up2Down,5-Left&Down2Up,6-Right&Up2Down,7-Right&Down2Up
        /// 8-CW,9-CCW
        /// </summary>
        public int ShowLocation { get; set; }
        public SerializableDictionary<string, string> CsvName2Property { get; set; }
        [XmlIgnore]
        public double LastPosition { get; set; }
        //[XmlIgnore]
        //private double absPosition;
        //public double AbsPosition
        //{
        //    get
        //    {
        //        return AxisOperator.GetAxisAbsEncoderPosition();
        //    }
        //}

        //[XmlIgnore]
        //public bool Home
        //{
        //    get
        //    {
        //        return AxisOperator.HomeFound[_axisNo - 1];
        //    }
        //}
        [XmlIgnore]
        public List<string> CardConfig { get; set; }
        public string OperatorName { get ; set ; }
        [XmlIgnore]
        public LogHelper Logger { get; set; }

        public Axis()
        {
            //this.Distance2MaxAcc = new Dictionary<double, double>();
            //this.Distance2Pos = new Dictionary<string, double>();
            this.SettingVelStart = new double[4] { 0, 0, 0, 0 };
            this.SettingVelEnd = new double[4] { 0, 0, 0, 0 };
            this.SettingVel = new double[4] { 100, 50, 10, 40 };
            this.SettingAcc = new double[4] { 0.01, 0.05, 0.1, 0.05 };
            this.SettingDec = new double[4] { 0.01, 0.05, 0.1, 0.05 };
            this.SettingSTime = new double[4] { 0.05, 0.05, 0.05, 0.05 };
            this.MotionPosition = new SerializableDictionary<string, double>();
            this.AxisLimits = new List<MotionLimit>();
            this.PositionLimits = new List<PositionLimit>();
            this.SensorLimits = new List<SensorLimit>();

            CsvName2Property = new SerializableDictionary<string, string>();
            CsvName2Property.Add("名称", nameof(Description));
            CsvName2Property.Add("所属模组", nameof(Module));
            CsvName2Property.Add("所属轴卡号", nameof(CardNo));
            CsvName2Property.Add("轴号", nameof(AxisNo));
            CsvName2Property.Add("ID", nameof(ID));
        }
        public void Copy(Axis axis)
        {
            SettingVelStart = axis.SettingVelStart;
            SettingVelEnd = axis.SettingVelEnd;
            SettingVel = axis.SettingVel;
            SettingAcc = axis.SettingAcc;
            SettingDec = axis.SettingDec;
            SettingSTime = axis.SettingSTime;
            MotionPosition = axis.MotionPosition;
            AxisLimits = axis.AxisLimits;
            PositionLimits = axis.PositionLimits;
            SensorLimits = axis.SensorLimits;
            ID = axis.ID;
            IsStep = axis.IsStep;
            Description = axis.Description;
            Module = axis.Module;
            IsRotateAxis = axis.IsRotateAxis;
            ConvertRate = axis.ConvertRate;
            PositionBand = axis.PositionBand;
            IsAbsoluteEncoder = axis.IsAbsoluteEncoder;
            HomeDirP = axis.HomeDirP;
            HomeMode = axis.HomeMode;
            HomeOffset = axis.HomeOffset;
            Distance2Pos = axis.Distance2Pos;
        }
        public Axis(short cardNo, short axisNo, string id, bool isStep, string description, string moduleName)
            : this()
        {
            this.CardNo = cardNo;
            this.AxisNo = axisNo;
            this.ID = id;
            this.IsStep = isStep;
            this.Description = description;
            this.Module = moduleName;
        }
        public short GetAxisNo()
        {
            return AxisNo;
        }
        public short GetCardNo()
        {
            return CardNo;
        }
        public int MM2Pulse(double mm)
        {
            if (IsRotateAxis)
            {
                mm %= 360;
                if (mm > 180)
                    mm -= 360;
                if (mm < -180)
                    mm += 360;
            }
            int pulseout = (int)(mm * ConvertRate);
            return pulseout;
        }
        public double Pulse2MM(int pulse)
        {
            double mmout = (pulse * 1.0 / ConvertRate);
            if (IsRotateAxis)
            {
                mmout %= 360;
                if (mmout > 180)
                    mmout = mmout - 360;
                if (mmout < -180)
                    mmout = mmout + 360;
            }
            return mmout;
        }
        public bool MoveConditionCheck(bool posDirection, out string stopReason)
        {
            stopReason = "";
            if (EmergencyStop)
            {
                Stop(true);
                stopReason = $"急停按下";
                //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}移动中急停按下!", Description), "Axis", 0));
                return false;
            }
            if (ServoWarn)
            {
                Stop(true);
                stopReason = $"轴:{this.Description}伺服报警中";
                //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}伺服报警!", Description), "Axis", 0));
                return false;
            }
            if (!NoCheckLimit)
            {
                if (NegativeLimit && !posDirection)
                {
                    Stop(true);
                    stopReason = $"轴:{this.Description}负极限到达";
                    //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}到达负极限!", Description), "Axis", 0));
                    return false;
                }
                if (posDirection && PositiveLimit)
                {
                    Stop(true);
                    stopReason = $"轴:{this.Description}正极限到达";
                    //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}到达正极限!", Description), "Axis", 0));
                    return false;
                }
            }
            if (AxisLimits != null && AxisLimits.Count > 0)
            {
                string errInfo = "";
                for (int i = 0; i < AxisLimits.Count; i++)
                {
                    if (AxisLimits[i].IsBreakRule(posDirection, out errInfo))
                    {
                        Stop(true);
                        stopReason = string.Format("轴{0}移动限制触发!原因:{1}", Description, errInfo);
                        //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}移动限制触发!原因:{1}", Description, errInfo), "Axis", 0));
                        return false;
                    }
                }
            }
            if (PositionLimits != null && PositionLimits.Count > 0)
            {
                string errInfo = "";
                for (int i = 0; i < PositionLimits.Count; i++)
                {
                    if (PositionLimits[i].IsBreakRule(posDirection, out errInfo))
                    {
                        Stop(true);
                        stopReason = string.Format("轴{0}位置限制触发!原因:{1}", Description, errInfo);
                        //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}移动限制触发!原因:{1}", Description, errInfo), "Axis", 0));
                        return false;
                    }
                }
            }
            if (SensorLimits != null && SensorLimits.Count > 0)
            {
                string errInfo = "";
                for (int i = 0; i < SensorLimits.Count; i++)
                {
                    if (SensorLimits[i].IsBreakRule(posDirection, out errInfo))
                    {
                        Stop(true);
                        stopReason = string.Format("轴{0}感应器限制触发!原因:{1}", Description, errInfo);
                        //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}移动限制触发!原因:{1}", Description, errInfo), "Axis", 0));
                        return false;
                    }
                }
            }
            return true;
        }
        public bool InPositionCheck(double destination)
        {
            DateTime now = DateTime.Now;
            while (Math.Abs(this.Position - destination) > PositionBand)
            {
                TimeSpan ts = DateTime.Now - now;
                if (ts.Seconds * 1000 + ts.Milliseconds > 1000)
                {
                    return false;
                }
                Thread.Sleep(2);
            }
            return true;
        }
        public void ClearErr()
        {
            AxisOperator.ClearAxisStatus(CardNo, AxisNo);
        }
        public void ClearAlarm()
        {
            AxisOperator.ResetServoWarn(CardNo, AxisNo);
        }
        public void SetServoOn()
        {
            AxisOperator.SetAxisServoOn(CardNo, AxisNo);
        }
        public void SetServoOff()
        {
            AxisOperator.SetAxisServoOff(CardNo, AxisNo);
        }
        public bool MoveContinuous(bool positiveDirection, out string stopReason, AxisSpeed speed = null)
        {
            StopMovement = false;
            CurrentDirection = positiveDirection;
            ClearErr();
            if (!Ready)
            {
                stopReason = $"轴:{Description}未达运动条件";
                return false;
            }
            if (!MoveConditionCheck(positiveDirection, out stopReason))
                return false;
            if (speed != null)
            {
                SetSpeed(speed);
            }
            else
            {
                SetSpeed(SpeedType.Manual);
            }
            if (_vel == 0 || _acc == 0 || _dec == 0)
            {
                stopReason = $"轴:{Description}未设置移动速度";
                _inMove = false;
                return false;
            }
            if (_vel == 0 || _acc == 0 || _dec == 0)
            {
                _inMove = false;
                return false;
            }
            if (!AxisOperator.AxisMoveContinous(CardNo, AxisNo, positiveDirection ? MoveDirection.Positive : MoveDirection.Negative, new AxisSpeed() { VelStart = _velStart, Vel = _vel, VelEnd = _velEnd, Acc = _acc, Dec = _dec }))
            {
                stopReason = $"轴:{Description}运动指令发送失败";
                return false;
            }
            return true;
        }
        public void AxisChangeSpeed(double speed)
        {
            double setVel = AxisOperator.VelUnitConvert(MM2Pulse(speed));
            AxisOperator.AxisChangeSpeed(CardNo, AxisNo, new AxisSpeed() { VelStart = _velStart, Vel = setVel, VelEnd = _velEnd, Acc = _acc, Dec = _dec, STime = _sTime });
        }
        public bool MoveAbsolute(double destination, out string stopReason, MotionWorkMode workMode, AxisSpeed speed = null, bool wait = true, double changePosition = 99999)
        {
            _inMove = false;
            StopMovement = false;
            stopReason = "";
            ClearErr();
            if (!Ready)
            {
                stopReason = $"轴:{Description}未达运动条件";
                return false;
            }
            double movetime = 0;
            if (!_inMove)
                _inMove = true;
            else
            {
                stopReason = $"轴:{Description}已在运动中";
                return false;
            }
            if (Math.Abs(destination - Position) < 0.005)
            {
                _inMove = false;
                return true;
            }
            bool direction = destination - Position >= 0;
            CurrentDirection = direction;
            if (!MoveConditionCheck(direction, out stopReason))
            {
                _inMove = false;
                return false;
            }
            if (speed != null)
            {
                SetSpeed(speed);
            }
            else
            {
                SpeedType speedType = SpeedType.Manual;
                switch (workMode)
                {
                    case MotionWorkMode.Auto:
                        speedType = SpeedType.Work;
                        break;
                    case MotionWorkMode.Manual:
                        speedType = SpeedType.Manual;
                        break;
                    case MotionWorkMode.TryRun:
                        speedType = SpeedType.TryRun;
                        break;
                }
                SetSpeed(speedType);
            }
            if (_vel == 0 || _acc == 0 || _dec == 0)
            {
                stopReason = $"轴:{Description}未设置移动速度";
                _inMove = false;
                return false;
            }

            if (changePosition != 99999)
            {
                Task.Run(() =>
                {
                    while (true && !StopMovement)
                    {
                        if (Math.Abs(this.Position - changePosition) <= 3)
                        {
                            AxisOperator.AxisChangeSpeed(CardNo, AxisNo, new AxisSpeed() { Vel = _changedVel, Acc = _changedAcc });
                            break;
                        }
                        Thread.Sleep(0);
                    }
                });
            }

            double offset = 0;
            offset = Math.Abs(Position - destination);
            movetime = 2 * offset / Vel;
            if (!AxisOperator.AxisMoveAbsolute(CardNo, AxisNo, (int)MM2Pulse(destination), new AxisSpeed() { VelStart = _velStart, Vel = _vel, VelEnd = _velEnd, Acc = _acc, Dec = _dec, STime = _sTime }))
            {
                stopReason = $"轴:{Description}运动指令发送失败";
                return false;
            }
            //命令一旦发出，就认为轴的历史位置 已经更新为目标位了 
            //自动模式下记录lastposition
            if (workMode == MotionWorkMode.Auto)
                LastPosition = destination;

            if (!wait)
            {
                _inMove = false;
                return true;
            }

            DateTime now = DateTime.Now;
            StopMovement = false;
            while (!Ready && !StopMovement)
            {
                if (!MoveConditionCheck(direction, out stopReason))
                {
                    _inMove = false;
                    return false;
                }
                //TimeSpan ts = DateTime.Now - now;
                //if (ts.Seconds * 1000 + ts.Milliseconds > movetime * 1000 + 1000)
                //{
                //    //MachineMessage.CallException(ExceptionType.FatalErr, "Axis", string.Format("轴{0}移动中超时!", Description));
                //    this.Stop(false);
                //    _inMove = false;
                //    return false;
                //}
                Thread.Sleep(2);
            }

            if (StopMovement)
            {
                StopMovement = false;
                Stop(false);
                _inMove = false;
                stopReason = $"轴:{Description}被人为终止运动";
                //这种人为终止的情况，自动情况下，也需要更新历史位置  例如 光栅触碰 
                if (workMode == MotionWorkMode.Auto)
                    LastPosition = destination;
                return false;
            }

            if (!MoveConditionCheck(direction, out stopReason))
            {
                _inMove = false;
                return false;
            }

            //StopType stopType = AxisOperator.GetStopReason(_cardNo, _axisNo);
            //if(stopType != StopType.Normal && stopType != StopType.Cmd)
            //{
            //    stopReason = $"轴:{Description}异常停止,原因:{EnumHelper.GetEnumDescriptionFromValue(stopType)}";
            //    return false;
            //}
            if (!IsStep)
            {
                if (!InPositionCheck(destination))
                {
                    stopReason = $"轴:{Description}到位超时";
                    //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}到位超时", Description), "Axis", 0));
                    return false;
                }
            }

            _inMove = false;
            return true;
        }
        public bool WaitAxisInPosition(double destination, MotionWorkMode workMode, out string stopReason)
        {
            bool direction = destination - Position >= 0;
            DateTime now = DateTime.Now;
            StopMovement = false;
            while (!Ready && !StopMovement)
            {
                if (!MoveConditionCheck(direction, out stopReason))
                {
                    _inMove = false;
                    return false;
                }
                //TimeSpan ts = DateTime.Now - now;
                //if (ts.Seconds * 1000 + ts.Milliseconds > movetime * 1000 + 1000)
                //{
                //    //MachineMessage.CallException(ExceptionType.FatalErr, "Axis", string.Format("轴{0}移动中超时!", Description));
                //    this.Stop(false);
                //    _inMove = false;
                //    return false;
                //}
                Thread.Sleep(2);
            }

            if (StopMovement)
            {
                StopMovement = false;
                Stop(false);
                _inMove = false;
                stopReason = $"轴:{Description}被人为终止运动";
                //这种人为终止的情况，自动情况下，也需要更新历史位置  例如 光栅触碰 
                if (workMode == MotionWorkMode.Auto)
                    LastPosition = destination;
                return false;
            }

            if (!MoveConditionCheck(direction, out stopReason))
            {
                _inMove = false;
                return false;
            }

            //StopType stopType = AxisOperator.GetStopReason(_cardNo, _axisNo);
            //if (stopType != StopType.Normal && stopType != StopType.Other && stopType != StopType.Cmd)
            //{
            //    _inMove = false;
            //    stopReason = $"轴:{Description}异常停止,原因:{EnumHelper.GetEnumDescriptionFromValue(stopType)}";
            //    return false;
            //}
            if (!IsStep)
            {
                if (!InPositionCheck(destination))
                {
                    stopReason = $"轴:{Description}到位超时";
                    //MachineMessageScheduler.Instance.Add(new MachineMessage(ExceptionType.NormalError, string.Format("轴{0}到位超时", Description), "Axis", 0));
                    return false;
                }
            }
            _inMove = false;
            //自动模式下记录lastposition
            if (workMode == MotionWorkMode.Auto)
                LastPosition = destination;
            return true;
        }
        public void ClearOffset()
        {
            throw new NotImplementedException();
        }
        public bool GoHome(short homeMode, bool homeDir, bool isWait = true, int timeOut = 120000)
        {
            //AxisOperator.IsHomeFinish[AxisNo - 1] = false;
            AxisOperator.AxisGoHome(CardNo, AxisNo, homeMode, homeDir, new AxisSpeed() { VelStart = _velStart, Vel = _vel, VelEnd = _velEnd, Acc = _acc, Dec = _dec });
            if (isWait)
            {
                Thread.Sleep(200);
                DateTime startTime = DateTime.Now;
                TimeSpan ts = DateTime.Now - startTime;
                while (!AxisOperator.GetAxisHomeFound(CardNo, AxisNo) && !Ready && ts.TotalMilliseconds < timeOut)
                {
                    ts = DateTime.Now - startTime;
                    Thread.Sleep(20);
                }
                if (ts.TotalMilliseconds >= timeOut)
                    return false;
                Thread.Sleep(200);
                return true;
            }
            return true;
        }
        public bool WaitHome(int timeOut = 80000)
        {
            Thread.Sleep(200);
            DateTime startTime = DateTime.Now;
            TimeSpan ts = DateTime.Now - startTime;
            while (!AxisOperator.GetAxisHomeFound(CardNo, AxisNo) && !Ready && ts.TotalMilliseconds < timeOut)
            {
                ts = DateTime.Now - startTime;
                Thread.Sleep(2);
            }
            if (ts.TotalMilliseconds >= timeOut)
                return false;
            Thread.Sleep(200);
            return true;
        }
        public void Stop(bool now)
        {
            _inMove = false;
            AxisOperator.StopAxis(CardNo, AxisNo, now);
        }
        public void Zero()
        {
            AxisOperator.ZeroAxisCommand(CardNo, AxisNo);
            AxisOperator.ZeroAxisEncoder(CardNo, AxisNo);
        }
        public void SetSpeed(SpeedType speedType)
        {
            switch (speedType)
            {
                case SpeedType.Work:
                    VelStart = SettingVelStart[0];
                    VelEnd = SettingVelEnd[0];
                    Vel = SettingVel[0];
                    Acc = SettingAcc[0];
                    Dec = SettingDec[0];
                    STime = SettingSTime[0];
                    break;
                case SpeedType.Manual:
                    VelStart = SettingVelStart[1];
                    VelEnd = SettingVelEnd[1];
                    Vel = SettingVel[1];
                    Acc = SettingAcc[1];
                    Dec = SettingDec[1];
                    STime = SettingSTime[1];
                    break;
                case SpeedType.Home:
                    VelStart = SettingVelStart[2];
                    VelEnd = SettingVelEnd[2];
                    Vel = SettingVel[2];
                    Acc = SettingAcc[2];
                    Dec = SettingDec[2];
                    STime = SettingSTime[2];
                    break;
                case SpeedType.TryRun:
                    VelStart = SettingVelStart[3];
                    VelEnd = SettingVelEnd[3];
                    Vel = SettingVel[3];
                    Acc = SettingAcc[3];
                    Dec = SettingDec[3];
                    STime = SettingSTime[3];
                    break;
            }
        }
        public void SetSpeed(AxisSpeed speed)
        {
            VelStart = speed.VelStart;
            VelEnd = speed.VelEnd;
            Vel = speed.Vel;
            Acc = speed.Acc;
            Dec = speed.Dec;
            STime = speed.STime;
        }
        public void SetChangeSpeed(double changedVel, double changedAcc)
        {
            ChangedVel = changedVel;
            ChangedAcc = changedAcc;
        }
        public void Move2Point(string pointName, out string stopReason, MotionWorkMode workMode, AxisSpeed speed = null, bool wait = true, double changePosition = 99999)
        {
            if (MotionPosition.ContainsKey(pointName))
            {
                MoveAbsolute(MotionPosition[pointName], out stopReason, workMode, speed, wait, changePosition);
            }
            else
            {
                stopReason = $"{this.Description}不存在名为{pointName}的点位";
            }
        }
        public void Wait2Point(string pointName, MotionWorkMode workMode, out string stopReason)
        {
            if (MotionPosition.ContainsKey(pointName))
            {
                WaitAxisInPosition(MotionPosition[pointName], workMode, out stopReason);
            }
            else
            {
                stopReason = $"{this.Description}不存在名为{pointName}的点位";
            }
        }
        public bool IsNearPosition(string pointName, double posBand)
        {
            if (Math.Abs(MotionPosition[pointName] - this.Position) <= posBand)
                return true;
            return false;
        }
        public bool IsGreaterThanPosition(string pointName)
        {
            if (this.Position >= (MotionPosition[pointName] - 0.5))
                return true;
            else
                return false;
        }
        public bool IsGreaterThanPosition(double position)
        {
            if (this.Position >= (position - 0.5))
                return true;
            else
                return false;
        }
        public void SetCompareOut(short channel, short logic, List<double> positions)
        {
            List<int> pulses = positions.Select(x => MM2Pulse(x)).ToList();
            AxisOperator.ConfigureCompareOut(CardNo, (short)(AxisNo - 1), channel, logic, 30, pulses);
        }
        public void SetOperator(IAxis machineOperator)
        {
            this.AxisOperator = machineOperator;
        }
    }
    public enum SpeedType
    {
        Work,
        Manual,
        Home,
        TryRun,
    }
    public enum MotionWorkMode
    {
        Auto,
        Manual,
        TryRun,
    }
}
